home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 004a / pbwiz10.zip / PBWIZ.DOC < prev    next >
Text File  |  1991-12-03  |  36KB  |  871 lines

  1.                        The PowerBASIC Wizard's Library
  2.                        =-----------------------------=
  3.                                  Version 1.0
  4.  
  5.                PBWIZ  Copyright (c) 1991  Thomas G. Hanlin III
  6.  
  7.  
  8.  
  9. This is PBWiz, a library of assembly language and BASIC routines for use with
  10. PowerBASIC version 2.0.  Full source code is available with registration. The
  11. PBWiz collection is copyrighted and may be distributed only under the
  12. following conditions:
  13.  
  14.    1) No fee of over $10.00 may be charged for distribution.  This
  15.       restriction applies only to physical copies and is not meant to
  16.       prevent distribution by telecommunication services.
  17.  
  18.    2) All PBWiz files must be distributed together in original, unaltered
  19.       form.  This includes BIBLIO.TXT, CATALOG.TXT, PBWIZ.DOC, PBWIZ.NEW,
  20.       REGISTER.TXT, WHERE.BBS, and the two archives, INCLUDES and UNITS.
  21.  
  22.    3) No files may be added to the PBWiz collection.  This applies most
  23.       specifically to the practice of adding BBS ads to archives, which I
  24.       find seriously offensive.
  25.  
  26. You use this library at your own risk.  It has been tested by me on my own
  27. computer, but I will not assume any responsibility for any problems which
  28. PBWiz may cause you.  If you do encounter a problem, please let me know
  29. about it, and I will do my best to verify and repair the error.
  30.  
  31. It is expected that if you find PBWiz useful, you will register your copy.
  32. You may not use PBWiz routines in programs intended for sale unless you have
  33. registered.  Registration entitles you to receive the latest version of
  34. PBWiz, complete with full source code in assembly language and BASIC.  The
  35. assembly code is designed for the MASM 6.0 assembler and may require minor
  36. modifications if you wish to use it with OPTASM, TASM, or earlier versions of
  37. MASM.
  38.  
  39. Warning: Use of PBWiz for more than 30 days without registering has been
  40. determined to cause fatal nose warts in penguins!  It may also encourage the
  41. author to practice the tuba under your window at night.
  42.  
  43.                               Table of Contents                        page 2
  44.  
  45.  
  46.  
  47.  Overview and Legal Info .................................................. 1
  48.  
  49.  Table of Contents ........................................................ 2
  50.  
  51.  Archives ................................................................. 3
  52.  
  53.  Dates and Times .......................................................... 5
  54.  
  55.  Equipment Info ........................................................... 6
  56.  
  57.  Extended Math ............................................................ 9
  58.  
  59.  Graphics ................................................................ 12
  60.  
  61.  Mouse Support ........................................................... 15
  62.  
  63.  Strings ................................................................. 18
  64.  
  65.  Credits ................................................................. 21
  66.  
  67.                                    Archives                            page 3
  68.  
  69.  
  70.  
  71. When I started in the microcomputer industry, there were a variety of file
  72. archivers, all (more or less) compatible.  They did not provide compression,
  73. which was relegated to another large selection of more-or-less compatible
  74. utilities.  Then came SEA's ARC.  It was very slow, but it did compression as
  75. well as archiving, and included CRC checks so you could know whether the
  76. files were intact.  It swept the BBS scene in short order, becoming the new
  77. standard.  A few other archivers competed on about a level footing, providing
  78. only minor variances on the ARC theme.  Then SEA decided to sue one of the
  79. more successful competitors, Phil Katz (PKARC).  The end result was the ZIP
  80. standard... but in the chaos resulting from the breaking of the ARC standard,
  81. many other archivers came into being: ARJ, LZH, PAK, ZOO, and so forth.
  82.  
  83. PBWiz helps resolve the confusion by providing a single set of routines which
  84. allow you to view the contents of archives in any of the above-mentioned
  85. formats: ARC, ARJ, LZH, PAK, ZIP, or ZOO.  Only archive directories are
  86. provided at this time.  Other formats will also be added as they arise.  If
  87. you have details on the format of an archive that you'd like me to add,
  88. please send them my way.  I'll do what I can to get it into PBWiz.
  89.  
  90. This unit requires the STRING unit (discussed later) as well.  To use it in
  91. your program, you need to include both units:
  92.  
  93.    $INCLUDE "string.inc"      ' (only if you need STRING in your programs)
  94.    $INCLUDE "archives.inc"
  95.    $LINK "stringa.obj"
  96.    $LINK "stringb.pbu"
  97.    $LINK "archives.pbu"
  98.  
  99. Viewing archive directories is handled in roughly the same fashion as you
  100. might view a DOS file directory.  This makes it possible to treat an archive
  101. and a subdirectory in a similar manner.
  102.  
  103. When you're looking for the first file in an archive, use the FindFirstA
  104. function.  You must specify the archive name and a file name.  The archive
  105. name may include a drive and path specification, and does not need to have
  106. the archive extension.  If you leave off the extension, FindFirstA will use
  107. the first archive it comes across that matches the rest of the specification.
  108. Note that the archive specification may not contain wildcards.  In contrast,
  109. the search file name may not contain drive or path specs, but may contain
  110. wildcards.
  111.  
  112.    CALL FindFirstA (Archive$, Filename$, ErrCode%)
  113.  
  114.                                    Archives                            page 4
  115.  
  116.  
  117.  
  118. If there are no files to be found, or if the archive specification was bad,
  119. an error code will be returned.  If there was no error, there may well be
  120. more files to be found.  You can find each of them with FindNextA:
  121.  
  122.    CALL FindNextA (ErrCode%)
  123.  
  124. Of course, just finding a matching file doesn't do you much good unless you
  125. can retrieve information about it.  You can use any of the following routines
  126. to provide information about a matched file:
  127.  
  128.    Nam$ = GetNameA$
  129.    Dat$ = GetDateA$
  130.    Tim$ = GetTimeA$
  131.    CRC$ = GetCRCA$
  132.    StorageMethod$ = GetStoreA$
  133.  
  134.    CALL GetSizeA (OriginalSize&, CurrentSize&)
  135.  
  136. When you're done viewing an archive, be sure to close it:
  137.  
  138.    CALL CloseA
  139.  
  140. Let's try an example.  Given that you've already written the $INCLUDE and
  141. $LINK lines as specified on the previous page, you could see all of the files
  142. in an archive using a program like this:
  143.  
  144.    CALL FindFirstA (Archive$, "*.*", ErrCode%)
  145.    DO UNTIL ErrCode%
  146.       PRINT GetNameA$
  147.       CALL FindNextA (ErrCode%)
  148.    LOOP
  149.    CALL FCloseA
  150.  
  151. This program fragment also assumes that you have set Archive$ to the name of
  152. an archive.  It might be convenient to set it to the command line for testing
  153. purposes:
  154.  
  155.    Archive$ = UCASE$(LTRIM$(RTRIM$(COMMAND$)))
  156.  
  157.                                Dates and Times                         page 5
  158.  
  159.  
  160.  
  161. This unit allows you to validate and compare dates.  It also provides the day
  162. of the week, given the date.  Dates may not be before the year 1900.  Date
  163. strings may be in the form "01/01/91" or "01-01-1991" (the delimiter is not
  164. significant and years may be two or four digits; two-digit years will be
  165. assumed to be in the 20th century).
  166.  
  167. To use the routines in this unit, include the following lines at the top of
  168. your program:
  169.  
  170.    $INCLUDE "timedate.inc"
  171.    $LINK "timedate.pbu"
  172.  
  173. Let's start off with date validation.  It's often important to know if a date
  174. entered into your program is a valid date.
  175.  
  176.    IF GoodDate%(DateSt$) THEN PRINT "The date is valid."
  177.  
  178. It can also be helpful to know on which day of the week a given date falls.
  179.  
  180.    Day$ = WeekDay$(DateSt$)
  181.  
  182. There are many useful things you can accomplish by turning a date into a
  183. number which represents that date (or vice versa).  This allows you to
  184. compare two dates, which is important if you want to sort by date; find out
  185. what the date will be in a given number of days, or what it was some number
  186. of days ago; find the number of days between two dates; display a calendar;
  187. and so forth.  This is easy to do with PBWiz:
  188.  
  189.    DateNr& = Date2Num&(DateSt$)
  190.  
  191.    DateSt$ = Num2Date$(DateNr&)
  192.  
  193. The DateNr& represents the number of days since January 1, 1900.  This is
  194. less than 65,535 for dates that go up to around the year 2070 or so, so you
  195. may wish to store the dates in compressed two-byte form if your required
  196. range of dates is not that large:
  197.  
  198.    CrunchDate% = CVI(LEFT$(MKL$(DateNr&), 2))
  199.  
  200. This can be reversed simply:
  201.  
  202.    DateNr& = CVL(MKI$(CrunchDate%) + STRING$(2, 0))
  203.  
  204. Note that dates crunched this way are only useful for storage purposes, since
  205. the numbers greater than 32,767 are stored as negative numbers due to the
  206. signed integer format BASIC uses.  You must uncompress them before doing any
  207. comparisons or date calculations.  Still, at half the size, it can be worth
  208. the hassle to convert back and forth.
  209.  
  210.                                Equipment Info                          page 6
  211.  
  212.  
  213.  
  214. The equipment unit gives you information about the computing environment.
  215. This includes both installed software and hardware.  You can use the
  216. equipment information routines by including these lines in your program:
  217.  
  218.    $INCLUDE "equipmen.inc"
  219.    $LINK "equipmen.obj"
  220.  
  221. The first function allows you to determine if an "enhanced" keyboard
  222. (101-key) is installed.  It may not be able to figure out what the keyboard
  223. is on some older not-quite-clone PCs, in which case it will take the safe way
  224. out and report that there is no enhanced keyboard.  This function returns -1
  225. if there is an enhanced keyboard present, 0 if not.
  226.  
  227.    Enhanced% = KbdType%
  228.  
  229. Want to know the type of processor (CPU) being used?  Can do!
  230.  
  231.    CPU% = Processor%
  232.  
  233. The results will be reported as a number which can be decoded as follow:
  234.  
  235.    0    NEC V20
  236.    1    8088 or 8086
  237.    2    80186
  238.    3    80286
  239.    4    80386 or 80486
  240.  
  241. If anyone knows how to differentiate between an 80386 and an 80486, please
  242. let me know.  I've only seen one test which could do it, and it wasn't
  243. reliable.
  244.  
  245. Maybe you'd like to check for a CD-ROM drive:
  246.  
  247.    Drives% = CDROM%
  248.  
  249. This tells you how many logical drives exist, if there is a CD-ROM available.
  250. If not, it will return 0.  Note that the CD-ROM installation check conflicts
  251. with the GRAPHICS.COM installation check for DOS 4.0, due to some screw-up at
  252. IBM or Microsoft.  I'm not yet sure whether DOS 5.0 is similarly afflicted.
  253.  
  254. The number of floppy drives installed is retrieved like this:
  255.  
  256.    Drives% = Floppies%
  257.  
  258.                                Equipment Info                          page 7
  259.  
  260.  
  261.  
  262. Now, there may be up to four floppy drives in a system; however, the AT CMOS
  263. data area only directly supports two.  This makes it easy to find out what
  264. kind of drives the first two are, but not the second two.  Oh well, guess
  265. we'll have to settle for what we can get, right?
  266.  
  267.    CALL FloppyType (Drive1, Drive2)
  268.  
  269. The results from FloppyType are returned as follows:
  270.  
  271.    0    no drive
  272.    1    5 1/4"    360K
  273.    2    5 1/4"    1.2M
  274.    3    3 1/2"    720K
  275.    4    3 1/2"    1.44M
  276.  
  277. Result codes of 5-7 are available, but not yet defined.  One might guess that
  278. the 2.88M drive supported by DOS 5.0 will be drive type 5.  Has anybody seen
  279. one of those puppies yet?
  280.  
  281. New memory types sure have burgeoned over the years... expanded, extended,
  282. and now XMS.  There are routines to check all of these:
  283.  
  284.    BaseExt& = AllExtMem&     ' amount of extended memory actually installed
  285.    NowExt& = GetExtM&        ' amount of BIOS extended memory available
  286.  
  287.    CALL GetEMSm (TotalPages%, FreePages%)    ' amount of expanded memory
  288.  
  289.    CALL GetXMSm (LargestFree&, TotalFree&)   ' amount of XMS memory
  290.  
  291. When you're dealing with extended memory, whether it be BIOS-type or using
  292. the XMS standard, the results are returned in kilobytes.  Multiply 'em by
  293. 1024 to convert to bytes.  When you're dealing with expanded memory (EMS),
  294. the results are in pages of 16,384 bytes.
  295.  
  296. I might note, by the way, that Microsoft seems to have intentionally crippled
  297. the XMS standard.  It can only support a maximum of 64 megabytes.  This may
  298. seem like a lot now, but I can remember when my first PC (a Compaq portable)
  299. was the awe of the neighborhood with 384K RAM!  A few years down the road,
  300. the artificial limitations of XMS are going to be a real nuisance.
  301.  
  302. A few more routines to get the versions of the EMS and XMS drivers, if any:
  303.  
  304.    CALL GetEMSv (MajorV%, MinorV%)
  305.    CALL GetXMSv (MajorV%, MinorV%)
  306.  
  307. These return the major and minor version numbers as two separate integers.
  308. For example, EMS 4.0 would return major version 4, minor version 0.
  309.  
  310.                                Equipment Info                          page 8
  311.  
  312.  
  313.  
  314. It's nice to know a little about the operating environment.  With the below
  315. routines, you can find out what the DOS version is; what version of 4DOS, if
  316. any, is in use; and whether Microsoft Windows is running.
  317.  
  318.    CALL GetDOSv (MajorV%, MinorV%)
  319.    CALL Get4DOSv (MajorV%, MinorV%)
  320.    CALL WinCheck (MajorV%, MinorV%)
  321.  
  322. These return results as major and minor version numbers, as discussed on the
  323. previous page.  The Get4DOSv and WinCheck routines return zeroes if 4DOS and
  324. Windows, respectively, are not available.
  325.  
  326. There are a couple of curious features of GetDOSv to keep in mind.  If the
  327. version is 10 or higher, you're running in OS/2 compatibility mode.  DOS
  328. version 10 is actually OS/2 1.0, version 20 is OS/2 2.0, and so on.
  329. Secondly, if you're using DOS 5.0, the version reported may not be 5.0-- DOS
  330. 5.0 can be told to reply with a lower version number to allow some older
  331. software (which checks for a specific DOS version) to run properly.
  332.  
  333. One final routine that should be of some value is the one that allows you to
  334. find out what kind of display is available.  It tells you the specific
  335. adapter and whether the display is color or monochrome.  There is one case in
  336. which it can be confused, however-- if the adapter is CGA, the display is
  337. assumed to be color, since there is no way for the computer to know any
  338. differently.  So, although this routine provides a good idea of what is
  339. available, it would be a good idea to provide an option to tell the program
  340. that a monochrome display is attached.  Microsoft normally uses "/B" for this
  341. purpose, so that might be a good standard to stick with.
  342.  
  343.    CALL GetDisplay (Adapter%, Mono%)
  344.    IF Mono% THEN
  345.       PRINT "Monochrome monitor"
  346.    ELSE
  347.       PRINT "Color monitor"
  348.    END IF
  349.    SELECT CASE Adapter%
  350.       CASE 1: PRINT "MDA"
  351.       CASE 2: PRINT "Hercules"
  352.       CASE 3: PRINT "CGA"
  353.       CASE 4: PRINT "EGA"
  354.       CASE 5: PRINT "MCGA"
  355.       CASE 6: PRINT "VGA"
  356.    END SELECT
  357.  
  358.                                 Extended Math                          page 9
  359.  
  360.  
  361.  
  362. The extended math unit provides an expression evaluator and extensions to
  363. BASIC's math.  The math extensions include hyperbolic and inverse trig
  364. functions, a few handy constants, conversions, and more.  You can use the new
  365. math routines by including this at the top of your program:
  366.  
  367.    $INCLUDE "extmath.inc"
  368.    $LINK "extmath.pbu"
  369.  
  370. The expression evaluator allows you to find the result of an expression
  371. contained in a string.  Normal algebraic precedence is used, e.g. 4+3*5
  372. evaluates to 19.  The usual numeric operators (*, /, +, -, ^) are supported
  373. (multiply, divide, add, subtract, and raise to a power).  Use of negative
  374. numbers is just fine, of course.  Parentheses for overriding the default
  375. order of operations are also supported.
  376.  
  377. You may use either a double asterisk ("**") or a caret ("^") symbols to
  378. indicate exponentiation.
  379.  
  380. To evaluate an expression, you pass it to the evaluator as a string.  You
  381. will get back either an error code or a single-precision result.  Try this
  382. example to see how the expression evaluator works:
  383.  
  384.    $STACK 4096
  385.    $INCLUDE "extmath.inc"
  386.    $LINK "extmath.pbu"
  387.    DO
  388.       INPUT "Expression? "; Expr$
  389.       IF LEN(Expr$) THEN
  390.          CALL Evaluate (Expr$, Result!, ErrCode%)
  391.          IF ErrCode% THEN
  392.             PRINT "Invalid expression.  Error = "; ErrCode%
  393.          ELSE
  394.             PRINT "Result: "; Result!
  395.          END IF
  396.       END IF
  397.    LOOP WHILE LEN(Expr$)
  398.    END
  399.  
  400. An expression evaluator adds convenience to any program that needs to accept
  401. numbers.  Why make someone reach for a calculator when number crunching is
  402. what a computer does best?
  403.  
  404. NOTE: The expression evaluator uses recursion and will require more than the
  405. default amount of stack space.  That's why the $STACK metacommand is used.
  406.  
  407.                                 Extended Math                         page 10
  408.  
  409.  
  410.  
  411. The new math functions are pretty much self-explanatory, so I'll just list
  412. them here.  A few general notes are given on the next page.
  413.  
  414.    Result% = GCDI%(Nr1%, Nr2%)         ' greatest common denominator
  415.  
  416.    Result& = GCDL&(Nr1&, Nr2&)         ' greatest common denominator
  417.  
  418.    Result! = ArcCosHS!(Nr!)            ' inverse hyperbolic cosine
  419.    Result! = ArcSinHS!(Nr!)            ' inverse hyperbolic sine
  420.    Result! = ArcTanHS!(Nr!)            ' inverse hyperbolic tangent
  421.    Result! = ArcCosS!(Nr!)             ' arc cosine  (1 >= Nr >= -1)
  422.    Result! = ArcSinS!(Nr!)             ' arc sine    (1 >= Nr >= -1)
  423.    Result! = ErfS!(Nr!)                ' error function
  424.    Result! = FactS!(Nr%)               ' factorial
  425.    Result! = CotS!(Nr!)                ' cotangent
  426.    Result! = CscS!(Nr!)                ' cosecant
  427.    Result! = SecS!(Nr!)                ' secant
  428.    Result! = CosHS!(Nr!)               ' hyperbolic cosine
  429.    Result! = SinHS!(Nr!)               ' hyperbolic sine
  430.    Result! = TanHS!(Nr!)               ' hyperbolic tangent
  431.    Result! = Deg2RadS!(Nr!)            ' convert degrees to radians
  432.    Result! = Rad2DegS!(Nr!)            ' convert radians to degrees
  433.    Result! = Cent2Fahr!(Nr!)           ' convert centigrade to Fahrenheit
  434.    Result! = Fahr2Cent!(Nr!)           ' convert Fahrenheit to centigrade
  435.    Result! = Kg2Pound!(Nr!)            ' convert kilograms to pounds
  436.    Result! = Pound2Kg!(Nr!)            ' convert pounds to kilograms
  437.    Pi! = PiS!                          ' the constant "pi"
  438.    e! = eS!                            ' the constant "e"
  439.  
  440.    Result# = ArcCosHD#(Nr#)            ' inverse hyperbolic cosine
  441.    Result# = ArcSinHD#(Nr#)            ' inverse hyperbolic sine
  442.    Result# = ArcTanHD#(Nr#)            ' inverse hyperbolic tangent
  443.    Result# = ArcCosD#(Nr#)             ' arc cosine  (1 >= Nr >= -1)
  444.    Result# = ArcSinD#(Nr#)             ' arc sine    (1 >= Nr >= -1)
  445.    Result# = ErfD#(Nr#)                ' error function
  446.    Result# = FactD#(Nr%)               ' factorial
  447.    Result# = CotD#(Nr#)                ' cotangent
  448.    Result# = CscD#(Nr#)                ' cosecant
  449.    Result# = SecD#(Nr#)                ' secant
  450.    Result# = CosHD#(Nr#)               ' hyperbolic cosine
  451.    Result# = SinHD#(Nr#)               ' hyperbolic sine
  452.    Result# = TanHD#(Nr#)               ' hyperbolic tangent
  453.    Result# = Deg2RadD#(Nr#)            ' convert degrees to radians
  454.    Result# = Rad2DegD#(Nr#)            ' convert radians to degrees
  455.    Pi# = PiD#                          ' the constant "pi"
  456.    e# = eD#                            ' the constant "e"
  457.  
  458.                                 Extended Math                         page 11
  459.  
  460.  
  461.  
  462. Like BASIC's trig functions, these trig functions expect the angle to be in
  463. radians.  Conversion functions are provided in case you prefer degrees.
  464.  
  465. Note that there is no ArcTanS! or ArcTanD# function for the simple reason
  466. that BASIC supplies an ATN function.
  467.  
  468. Constants are expressed to the maximum precision available.
  469.  
  470. If you are not familiar with variable postfix symbols, here's a summary:
  471.  
  472.    Symbol   Meaning             Range (approximate)
  473.    ------   --------            -----------------------------------
  474.      %      integer             +- 32767
  475.      &      long integer        +- 2 * 10^9
  476.      !      single precision    +- 1 * 10^38   (7-digit precision)
  477.      #      double precision    +- 1 * 10^308  (15-digit precision)
  478.  
  479. See your BASIC manual or PowerBASIC's online help for further details.
  480.  
  481.                               Graphics Support                        page 12
  482.  
  483.  
  484.  
  485. I was rather surprised to find that PowerBASIC lacks support for one of the
  486. standard VGA modes-- SCREEN 13, the 320x200 256-color mode.  I immediately
  487. decided to add support for that mode: dots, lines, boxes, polygons, and (of
  488. course) text.  While I was at it, I thought I'd add support for a nonstandard
  489. VGA mode: 360x480 in 256 colors.  This mode will work on almost any plain VGA
  490. system, although it might not work on some older not-quite-compatible setups.
  491. I'll be adding other modes as I go along, including SuperVGA modes.  For now,
  492. there are only two modes:
  493.  
  494.    13    320x200, 256 colors, 40x25 text, standard (any VGA)
  495.    N0    360x480, 256 colors, 45x30 text, nonstandard (almost any VGA)
  496.  
  497. The graphics routines all use the same nomenclature: a G, followed by a mode
  498. number, followed by the specific name.  This generic naming convention is
  499. used so that this chapter can refer to all available modes.  For example, if
  500. I say "G#Color" and you're using mode 13, you'd actually use "G13Color" in
  501. your program.  Ok?
  502.  
  503. There are two sets of routines for each mode-- the ones written in ASM and
  504. the ones written in BASIC.  The file names for these will be suffixed with
  505. "A" for ASM and "B" for BASIC.  For instance, to use the SCREEN 13 routines,
  506. you would add the following at the top of your program:
  507.  
  508.    $INCLUDE "g13.inc"
  509.    $LINK "g13a.obj"
  510.    $LINK "g13b.pbu"
  511.  
  512. The first thing you will always have to do is to put the screen into the
  513. proper mode.  This is done with the G#Mode routine:
  514.  
  515.    CALL G#Mode (Graphics%)
  516.  
  517. Use 0 to switch to text mode or any other value to switch to graphics mode.
  518.  
  519. One difference between BASIC and BasWiz is that, instead of each "draw"
  520. command requiring a color parameter as in BASIC, the PBWiz library provides
  521. a separate color command:
  522.  
  523.    CALL G#Color (Foreground%, Background%)
  524.  
  525. The "foreground" color is used by all graphics routines.  The background
  526. color is used by the G#Cls routine.  Both foreground and background colors
  527. are used in the G#Write and G#WriteLn routines.
  528.  
  529.                               Graphics Support                        page 13
  530.  
  531.  
  532.  
  533. Here is a list of the corresponding routines, first BASIC, then PBWiz
  534. (replace the "#" with the appropriate mode number):
  535.  
  536.    ' get the color of a specified point
  537.    colour% = POINT(x%, y%)
  538.    colour% = G#GetPel%(x%, y%)
  539.  
  540.    ' set the color of a specified point
  541.    PSET (x%, y%), colour%
  542.    CALL G#Color (colour%, backgnd%): CALL G#Plot (x%, y%)
  543.  
  544.    ' draw a line of a specified color
  545.    LINE (x1%, y1%) - (x2%, y2%), colour%
  546.    CALL G#Color (colour%, backgnd%): CALL G#Line (x1%, y1%, x2%, y2%)
  547.  
  548.    ' draw a box frame of a specified color
  549.    LINE (x1%, y1%) - (x2%, y2%), colour%, B
  550.    CALL G#Color (colour%, backgnd%): CALL G#Box (x1%, y1%, x2%, y2%, 0)
  551.  
  552.    ' draw a box of a specified color and fill it in
  553.    LINE (x1%, y1%) - (x2%, y2%), colour%, BF
  554.    CALL G#Color (colour%, backgnd%): CALL G#Box (x1%, y1%, x2%, y2%, 1)
  555.  
  556.    ' clear the screen and home the cursor
  557.    CLS
  558.    CALL G#Cls
  559.  
  560.    ' get the current cursor position
  561.    Row% = CSRLIN: Column% = POS(0)
  562.    CALL G#GetLocate (Row%, Column%)
  563.  
  564.    ' set the current cursor position
  565.    LOCATE Row%, Column%
  566.    CALL G#Locate (Row%, Column%)
  567.  
  568.    ' display a string without a carriage return and linefeed
  569.    PRINT St$;
  570.    CALL G#Write (St$)
  571.  
  572.    ' display a string with a carriage return and linefeed
  573.    PRINT St$
  574.    CALL G#WriteLn (St$)
  575.  
  576. Note that PBWiz, unlike BASIC, allows both foreground and background colors
  577. for text in graphics mode.
  578.  
  579.                               Graphics Support                        page 14
  580.  
  581.  
  582.  
  583. If you need to print a number rather than a string, just use the BASIC
  584. function STR$ to convert it.  If you don't want a leading space, use this
  585. approach:
  586.  
  587.    St$ = LTRIM$(STR$(Number))
  588.  
  589. The PBWiz library has other routines which have no BASIC equivalent.  One
  590. allows you to get the current colors:
  591.  
  592.    CALL G#GetColor (Foreground%, Background%)
  593.  
  594. Circles and ellipses can be drawn with the Ellipse routine. This is similar
  595. to the BASIC CIRCLE statement.  You specify the center of the ellipse (X,Y),
  596. plus the X and Y radius values:
  597.  
  598.    CALL G#Ellipse (CenterX%, CenterY%, XRadius%, YRadius%)
  599.  
  600. A circle is an ellipse with a constant radius.  So, to draw a circle, just
  601. set both radius values to the same value.
  602.  
  603. As well as the usual points, lines, and ellipses, PBWiz also allows you to
  604. draw regular polygons: triangles, squares, pentagons, hexagons, and so on.
  605.  
  606.    CALL G#Polygon (X%, Y%, Radius%, Vertices%, Angle!)
  607.  
  608. The X% and Y% values represent the coordinates of the center of the polygon.
  609. The Radius% is the radius of the polygon (as if you were fitting it into a
  610. circle).  Vertices% is the number of angles (also the number of sides) for
  611. the polygon to have.  Angle! specifies the rotation of the polygon, and is
  612. specified in radians.
  613.  
  614.                                 Mouse Support                         page 15
  615.  
  616.  
  617.  
  618. The mouse unit provides full-featured mouse support.  You can see if a mouse
  619. is available and how many buttons it has, get the cursor position (either the
  620. current position or the position at the last press or release of a specified
  621. button), set the cursor position, change the cursor, set the mouse range, get
  622. hardware information about the mouse, and so on.
  623.  
  624. This unit is called MOUSE, so you access it by including the following lines
  625. at the top of your program:
  626.  
  627.    $INCLUDE "mouse.inc"
  628.    $LINK "mouse.obj"
  629.  
  630. There are two unusual mouse modes to be aware of.  One is text mode, which is
  631. mapped to a 640x200 virtual display.  So, to convert the results to text
  632. format, you need to divide the cursor position by eight and add one.  To
  633. convert from text format, subtract one and multiply by eight.
  634.  
  635. The second unusual mode is 320x200 CGA mode, which is also mapped to 640x200.
  636. To convert the coordinates to this mode, divide X by two.  To convert from
  637. this mode, multiply the X coordinate by two.
  638.  
  639. All other modes use the actual display coordinates instead of a bizarro
  640. virtual screen.  Why the peculiar CGA and text modes?  Well, evidently
  641. Microsoft never thought there'd be any video adapters besides MDA and CGA,
  642. and decided to create a single virtual screen size that worked for all modes.
  643. Not a bad idea, I guess, but rather shortsighted.  Oh well.
  644.  
  645. One other nuisance that you may run into is that the mouse cursor can't be
  646. directly turned on or off.  A "cursor visibility" count is maintained-- if
  647. the mouse cursor was turned on twice, you'll need to turn it off twice before
  648. it will actually disappear.
  649.  
  650. Before using the mouse, you must initialize it.  The initialization routine
  651. also checks to make sure that a mouse is installed and tells you how many
  652. buttons it has.  It's best to initialize the mouse after setting the screen
  653. mode, so the mouse driver understands what mode you're using.  Not all mouse
  654. drivers support all screen modes, but you can reasonably expect any current
  655. mouse driver to support MDA, CGA, EGA, and VGA.  Hercules graphics mode is
  656. rarely supported, as it must be set through direct hardware access rather
  657. than the standard techniques, so the mouse driver has little way of knowing
  658. that you've changed the mode.
  659.  
  660. The mouse routines will work equally well with two-button or three-button
  661. rodents.  The middle button functions will return 0 with two-button mice.
  662.  
  663. I won't go into great detail on these routines, because they're pretty much
  664. self-explanatory.  The mouse is a fairly easy device to deal with.
  665.  
  666.                                 Mouse Support                         page 16
  667.  
  668.  
  669.  
  670. You can initialize the mouse driver like so:
  671.  
  672.    Buttons% = MouseInit%
  673.  
  674. This returns the number of mouse buttons available.  If there is no mouse,
  675. zero will be returned.  Initialize the mouse after setting the screen mode.
  676.  
  677. You can make the mouse cursor visible or invisible.  It will function just as
  678. well in either state.  See the previous page for some quirks.
  679.  
  680.    CALL MouseShow       ' show the cursor
  681.    CALL MouseHide       ' hide the cursor
  682.  
  683. There are many ways to get the mouse cursor position.  You can get the
  684. current position, the position at which the mouse was located when a
  685. particular button was pressed, or the position when a button was released.
  686. If you choose a past position, you can also find out how many presses or
  687. releases of the button have taken place since you last checked.
  688.  
  689.    X% = MouseWhereX%         ' return current X coordinate
  690.    Y% = MouseWhereY%         ' return current Y coordinate
  691.  
  692.    CALL MouseLClick (Count%, X%, Y%)    ' left presses and posn at last press
  693.    CALL MouseMClick (Count%, X%, Y%)    ' middle presses & posn at last press
  694.    CALL MouseRClick (Count%, X%, Y%)    ' right presses & posn at last press
  695.  
  696.    CALL MouseLRelease (Count%, X%, Y%)  ' left releases and posn at last rel.
  697.    CALL MouseMRelease (Count%, X%, Y%)  ' middle releases & posn at last rel.
  698.    CALL MouseRRelease (Count%, X%, Y%)  ' right releases & posn at last rel.
  699.  
  700. If you'd prefer to find out which buttons are currently pressed, no problem:
  701.  
  702.    Pressed% = MouseLButton%      ' whether the left button is pressed
  703.    Pressed% = MouseMButton%      ' whether the middle button is pressed
  704.    Pressed% = MouseRButton%      ' whether the right button is pressed
  705.  
  706. Of course, if you can get the cursor position, you must be able to set it:
  707.  
  708.    CALL MouseLocate (X%, Y%)     ' set the mouse cursor position
  709.  
  710. The mouse cursor range can be restricted to a given area of the screen.  This
  711. area is expressed by giving the upper left corner and lower right corner of
  712. the rectangular area to which to restrict the cursor.
  713.  
  714.    CALL MouseWindow (X1%, Y1%, X2%, Y2%)
  715.  
  716.                                 Mouse Support                         page 17
  717.  
  718.  
  719.  
  720. There are a variety of cursor shapes available for graphics mode:
  721.  
  722.     0    hourglass (standard "please wait, I'm working" symbol)
  723.     1    pointing arrow (default)
  724.     2    pointing hand
  725.     3    crosshair
  726.     4    target (box in a box)
  727.     5    grabbing hand
  728.  
  729. If you have ideas for more, let me know and I'll see what I can do.
  730.  
  731. The cursor image is set like so:
  732.  
  733.    CALL MouseCursorG (CursorNr%)
  734.  
  735.                                    Strings                            page 18
  736.  
  737.  
  738.  
  739. One of the true strengths of BASIC lies in its powerful string handling
  740. capability.  I'd be remiss if I didn't provide extensions which improve it
  741. even further.  This unit can be accessed by including these lines at the top
  742. of your program:
  743.  
  744.    $INCLUDE "string.inc"
  745.    $LINK "stringa.obj"
  746.    $LINK "stringb.pbu"
  747.  
  748. The simplest of the PBWiz string routines may seem somewhat whimsical, but it
  749. has proven useful to me on several occasions in the past.  It reverses the
  750. order of characters in a string.
  751.  
  752.    CALL Reverse (St$)
  753.  
  754. One of the places this has come in useful is in searching a string from the
  755. end-- a reverse INSTR routine:
  756.  
  757.    CALL RInstr (MainSt$, SubSt$, Posn%)
  758.  
  759. Rather than returning the first occurrence of a substring within a main
  760. string, it returns the last occurrence.  Another handy string search allows
  761. you to search for various types of characters, rather than a specific
  762. substring:
  763.  
  764.    CALL TInstr (MainSt$, Types%, Posn%)
  765.  
  766. The type(s) may be specified using any combination of the following.  Just
  767. add them together.
  768.  
  769.     1    alphabetic
  770.     2    numeric
  771.     4    symbolic
  772.     8    control
  773.    16    graphics
  774.    32    space
  775.  
  776. Since you can search for any specific types, you can also readily invert the
  777. search to look for any characters that are NOT of a given type or types:
  778.  
  779.    Types% = NOT Types%
  780.  
  781. This gives you complete control.  A typical use for TInstr might be to clean
  782. up user input and make sure that it's valid.  It's also good for parsing.
  783.  
  784.                                    Strings                            page 19
  785.  
  786.  
  787.  
  788. Another routine that is useful for cleaning up and parsing user input is
  789. called Crunch.  It allows you to eliminate adjacent duplicates of a character
  790. or list of characters.  One use for this, for instance, would be to eliminate
  791. repeated spaces, converting an input string from "*.*    *.BAK  /B" to a more
  792. manageable "*.* *.BAK /B".
  793.  
  794.    Result$ = Crunch$(St$, CharList$)
  795.  
  796. There are a pair of routines that you'll find valuable if you need to check
  797. the validity of a string.  These are designed to be compatible with the
  798. Xmodem and Ymodem file transfer protocols, so you can use them for error
  799. checking in telecommunications as well.
  800.  
  801.    Chk% = CheckSum% (St$)
  802.  
  803.    CALL CRC16 (St$, HiCRC%, LoCRC%)
  804.  
  805. Another pair of string routines provide a simple encryption/decryption system
  806. for text.  The method used is not particularly secure but are very fast and
  807. will be adequate for many purposes.  As always, it helps to use a long and/or
  808. complex password.
  809.  
  810.    CALL Cipher (St$, Password$)
  811.    CALL CipherP (St$, Password$)
  812.  
  813. Both of these routines will encipher text on the first run-through and
  814. decipher on the second, so you can use the same routine either to encrypt or
  815. decrypt a message.  They are different in one respect: the encrypted result
  816. of Cipher may contain control characters, so it can't be used in a plain
  817. sequential-access file.  The CipherP routine does not allow use of extended
  818. ASCII characters (CHR$(128) - CHR$(255)), as it sets the high bit on each
  819. character after encrypting it.  This causes the results of CipherP to be
  820. printable (and useful in sequential-access files), although they will look
  821. very strange.
  822.  
  823. The strings are encrypted (or decrypted) in place.  This provides a certain
  824. extra measure of security for encryption-- the original plaintext strings are
  825. not left floating around in memory where someone might see them.
  826.  
  827. One function is as much a file manipulation routine as it is a string
  828. function.  It allows you to compare a file name to a file pattern (which may
  829. contain wildcards) to see if they match.  Only bare filespecs are supported--
  830. you may not use drive or path specifications in the names.
  831.  
  832.    IF MatchFile%(Pattern$, Filename$) THEN PRINT Filename$
  833.  
  834. This can be used in creating your own DOS-style utilities: DIR, COPY, and so
  835. forth.  Besides the usual "accept file if it matches" approach, it can also
  836. be used to implement the opposite: "exclude file if it matches."  This gives
  837. you more flexibility than DOS itself supplies.
  838.  
  839.                                    Strings                            page 20
  840.  
  841.  
  842.  
  843. The PowerBASIC compiler provides a very nice function called Extract$.  This
  844. allows you to retrieve a substring running from the left side of a main
  845. string to a specified character delimiter.  Not bad, but it might be handy to
  846. be able to grab a numbered substring from any part of a main string, and to
  847. be able to use a substring delimiter.  For instance, you might load a record
  848. from a database which contains an address, where each line is delimited by a
  849. carriage return and linefeed.  Rather than mucking around with Extract$,
  850. which really wasn't designed with that sort of thing in mind, you'd do better
  851. to use the PBWiz function called DelimExtract$:
  852.  
  853.    SubSt$ = DelimExtract$(St$, Delimiter$, Index%)
  854.  
  855. The index starts at 1 with the first substring.  If you choose the index of a
  856. substring which doesn't actually exist, a null string will be returned.
  857.  
  858.                                    Credits                            page 21
  859.  
  860.  
  861.  
  862. I'd like to thank Dave Navarro for letting me in on the world of PowerBASIC.
  863. His assistance has been most valuable to me in many respects.  Without him,
  864. this library would have taken much longer to get off the ground or would
  865. perhaps not even exist.  Dave runs the excellent Bard's Lair BBS-- see my
  866. WHERE.BBS file for more details.
  867.  
  868. I would also like to thank Spectra, publishers of PowerBASIC, for sending me
  869. the evaluation copy which led to my decision to write this library.
  870.  
  871.